package constants

import (
	"JVM/Jvmgo/GoToJVM/instructions/base"
	"JVM/Jvmgo/GoToJVM/runtimeData"
	"JVM/Jvmgo/GoToJVM/runtimeData/heap"
)

/*
这个指令作用总的来收即： Load a constant on to the operand stack
*/

// 将常量池的int，float，string类型参数推到栈顶
type LDC struct {
	base.Index8Instruction
}

// 是ldc的索引
type LDC_W struct {
	base.Index16Instruction
}

// 将 Long和Double类型参数推送到栈顶
type LDC2_W struct {
	base.Index16Instruction
}

// 由于只是索引宽度之间的关系，底层实现逻辑其实是一样的
func (self *LDC) Execute(frame *runtimeData.Frame) {
	_ldc(frame, self.Index)
}
func (self *LDC_W) Execute(frame *runtimeData.Frame) {
	_ldc(frame, self.Index)
}

func _ldc(frame *runtimeData.Frame, index uint) {
	stack := frame.OperandStack()
	class := frame.Method().Class()
	c := class.ConstantPool().GetConstant(index)

	switch c.(type) {
	case int32:
		stack.PushInt(c.(int32))
	case float32:
		stack.PushFloat(c.(float32))
	case string:
		internedStr := heap.JString(class.Loader(), c.(string))
		stack.PushRef(internedStr)
	case *heap.ClassRef:
		// 这里类索引也作为一种引用类型
		classRef := c.(*heap.ClassRef)
		classObj := classRef.ResolvedClass().JClass()
		stack.PushRef(classObj)
	default:
		panic("未支持类型！")
	}
}

func (self *LDC2_W) Execute(frame *runtimeData.Frame) {
	stack := frame.OperandStack()
	cp := frame.Method().Class().ConstantPool() // 获取运行时常量池
	c := cp.GetConstant(self.Index)

	switch c.(type) {
	case int64:
		stack.PushLong(c.(int64))
	case float64:
		stack.PushDouble(c.(float64))
	default:
		panic("java.lang.ClassFormatError")
	}
}
